/* memread.cpp
 *
 * try to maximize bandwidth by bombarding with memcpy
 *
 * working set size <= cache size
 */

#include <omp.h>
#include "bench.h"
#include <assert.h>

#include <string.h>
#include "papi_test.h"

#define AI 0

const int eventlist[] = {
    PAPI_TOT_INS,
    PAPI_L1_DCA,
    PAPI_L1_TCM,
    0
};

void stride(int* src, int startindex, int endindex, long num_accesses, int64_t block_size)
{
    int sum = 0;
    int index = startindex;
    int block_len = block_size / sizeof(int);
	int retval;
	int EventSet = PAPI_NULL;
	long long values;
    PAPI_event_info_t evinfo;
	char event_name[PAPI_MAX_STR_LEN];

    if ( ( retval = PAPI_create_eventset( &EventSet ) ) != PAPI_OK )
        test_fail( __FILE__, __LINE__, "PAPI_create_eventset", retval );
    for (int j = 0; eventlist[j] != 0; j++)
    {
        retval = PAPI_event_code_to_name( eventlist[j], event_name );

        if ( retval != PAPI_OK )
            test_fail( __FILE__, __LINE__, "PAPI_event_code_to_name", retval );

        if ( (retval = PAPI_add_event( EventSet, eventlist[j] ) ) != PAPI_OK )
            continue;

        if ( (retval = PAPI_get_event_info( eventlist[j], &evinfo )) != PAPI_OK )
            test_fail( __FILE__, __LINE__, "PAPI_get_event_info", retval );

        //printf( "\nEvent: %s\nShort: %s\nLong: %s\n\n",
        //        evinfo.symbol, evinfo.short_descr, evinfo.long_descr );

        PAPI_start(EventSet);
        if ( ( retval = PAPI_reset( EventSet ) ) != PAPI_OK )
            test_fail( __FILE__, __LINE__, "PAPI_reset", retval );

        volatile int dest = 0;
        for (long i = 0; i < num_accesses; i++)
        {
            // copy the block of memory
            for (int k = 0;k < block_len; k++)
                src[index + k] = dest;

            sum += src[index];

            index += block_len;
            if (index > endindex - block_len)
                index = startindex;
        }
        if ( ( retval = PAPI_read( EventSet, &values ) ) != PAPI_OK )
            test_fail( __FILE__, __LINE__, "PAPI_read", retval );

        PAPI_stop(EventSet, NULL);
        if ( ( retval =
                    PAPI_remove_event( EventSet, eventlist[j] ) ) != PAPI_OK )
            test_fail( __FILE__, __LINE__, "PAPI_remove_event", retval );

        printf("\nThread tid : %d, %s, %lld", omp_get_thread_num(), event_name, values);
    }
    PAPI_unregister_thread();
    finaldest[omp_get_thread_num()] = sum;
    return;
}
